package org.wheel.plugins.toolkit.sql.function;

import cn.hutool.core.util.StrUtil;
import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.core.SqlSegment;
import org.wheel.plugins.toolkit.sql.enums.SqlFunction;
import org.wheel.plugins.toolkit.sql.enums.SqlTimeUnit;
import org.wheel.plugins.toolkit.sql.helper.LambdaUtils;
import org.wheel.plugins.toolkit.sql.helper.SFunction;
import org.wheel.plugins.toolkit.sql.segment.SelectSegment;
import org.wheel.plugins.toolkit.sql.segment.SqlWindowUnit;

import java.util.function.Consumer;

/**
 * 函数工具 – 双写法入口
 */
public final class F {

    /* ========== 字符串字段版（无 Wrapper） ========== */
    public static FunctionBuilder sum(String column) {
        return fn(SqlFunction.SUM.name(), false, null).col(column);
    }
    public static FunctionBuilder count() {
        return fn(SqlFunction.COUNT.name(), false,null).col("*").as("count");
    }
    public static FunctionBuilder count(String column) {
        return fn(SqlFunction.COUNT.name(), false,null).col(StrUtil.blankToDefault(column, "*"));
    }
    public static FunctionBuilder count(String column, String columnAlias) {
        return fn(SqlFunction.COUNT.name(), false,null).col(column).as(columnAlias);
    }
    public static FunctionBuilder dateAdd(String column, int amount, SqlTimeUnit unit) {
        return fn(SqlFunction.DATE_ADD.name(), true, null).col(column).arg(amount).col(unit);
    }
    public static FunctionBuilder rowNumber() { return fn(SqlFunction.ROW_NUMBER.name(), true, null); }

    /* ========== Lambda 字段版（带 Wrapper） ========== */

    public static <T> FunctionBuilder distinct() {
        return distinct(null);
    }
    public static <T> FunctionBuilder distinct(SFunction<T, ?> column) {
        return fn(SqlFunction.DISTINCT.name(), false, null).col(column).distinct(true);
    }
    public static <T> FunctionBuilder distinct(String tableAlias, SFunction<T, ?> column) {
        return fn(SqlFunction.DISTINCT.name(), false, null).col(column).tableAlias(tableAlias);
    }
    public static <T> FunctionBuilder countDistinct(String tableAlias, SFunction<T, ?> column){
        return count(tableAlias, column).distinct(true);
    }
    public static <T> FunctionBuilder countDistinct(SFunction<T, ?> column){
        return countDistinct(null, column);
    }

    public static <T> FunctionBuilder sum(SFunction<T, ?> column) {
        return fn(SqlFunction.SUM.name(), false, null).col(column);
    }
    public static <T> FunctionBuilder sum(String tableAlias, SFunction<T, ?> column) {
        return fn(SqlFunction.SUM.name(), false, null).tableAlias(tableAlias).col(column);
    }
    public static <T> FunctionBuilder count(SFunction<T, ?> column) {
        return count(null,  column);
    }
    public static <T> FunctionBuilder count(String tableAlias, SFunction<T, ?> column) {
        return fn(SqlFunction.COUNT.name(), false, null).tableAlias(tableAlias).col(column);
    }
    public static <T> FunctionBuilder dateAdd(SFunction<T, ?> column, int amount, SqlTimeUnit unit, AbstractWrapper<?, ?> wrapper) {
        return fn(SqlFunction.DATE_ADD.name(), true,  wrapper).col(LambdaUtils.getColumn(column)).arg(amount).col(unit);
    }

    public static <T> FunctionBuilder jsonExtract(SFunction<T, ?> column, String path, AbstractWrapper<?, ?> wrapper){
        return fn(SqlFunction.JSON_EXTRACT.name(), true, wrapper)
                .col(LambdaUtils.getColumn(column))
                .arg(path);
    }

    public static FunctionBuilder fn(String funcName, SqlSegment segment){
        return fn(funcName, false, null).col(segment);
    }

    public static <T> FunctionBuilder fn(String funcName, SqlSegment segment, SFunction<T, ?> columnAlias){
        return fn(funcName, false, null).col(segment).as(columnAlias);
    }

    public static FunctionBuilder fn(String funcName, SqlSegment segment, String columnAlias){
        return fn(funcName, false, null).col(segment).as(columnAlias);
    }
    /* ========== 内部工厂 ========== */
    private static FunctionBuilder fn(String funcName, boolean usePlugin, AbstractWrapper<?, ?> wrapper) {
        if(usePlugin){
            return FunctionBuilder.plugin(funcName,  wrapper);
        }
        return FunctionBuilder.fn(funcName, wrapper);
    }

    /* ========== 原始列片段 ========== */
    public static SelectSegment col(String column) {
        return () -> column;
    }
}